關於活動報名以及身份驗證的流程,已經在昨天的文章中規劃好了,今天會著手將 Repository 與 Controller 儲存報名者資訊的功能實現出來。
在昨天,我們將儲存報名者資訊,EventsEnroll 的 Model 與 Table 建立好,而 Repository 也要加入將資料存到 EventsEnroll 的 Function。
依據報名功能流程的規劃,Repository 會加入兩個功能:
(不太確定 Function Name 取這麼長是不是能被接受的QQ)
public async Task<bool> SaveUserInfoToEventsEnrollAsync(EventsEnroll eventsEnroll)
{
_appDbContext.EventsEnroll.Add(eventsEnroll);
var count = await _appDbContext.SaveChangesAsync();
return count > 0;
}
public async Task<bool> DeleteUserInfoFromEventsEnrollAsync(EventsEnroll eventsEnroll)
{
_appDbContext.EventsEnroll.Remove(eventsEnroll);
var count = await _appDbContext.SaveChangesAsync();
return count > 0;
}
public async Task<int> GetApplicateQtyByEventIdAsync(int eventId)
{
var qty = await _appDbContext.EventsEnroll.Where(
ee => ee.Events.Id == eventId
).CountAsync();
return qty;
}
做一個 C# 版的 SQL Between 功能,判斷當下時間是否在傳入的 Events 的報名時間範圍內,以及判斷現在 EventsEnroll 的資料數量(EventId 為現在選擇的活動)是否與該活動人數上限相同:
public class EventsApplyServices
{
private readonly IEventsRepository _eventsRepository;
public EventsApplyServices(IEventsRepository eventsRepository)
{
_eventsRepository = eventsRepository;
}
public bool IsInEventsSalesTime(Events @event)
{
var salesTimeStart = @event.SaleTimeStart;
var salesTimeEnd = @event.SaleTimeEnd;
var dateTimeNow = DateTime.Now;
if (salesTimeStart <= dateTimeNow && salesTimeEnd >= dateTimeNow )
return true;
return false;
}
public async Task<bool> IsApplicationLimitedQtyFull(Events @event)
{
var applicationLimitedQty = @event.EventsInfo.ApplicationLimitedQty;
var eventsApplicationQty = await _eventsRepository.GetApplicateQtyByEventIdAsync(@event.Id);
return applicationLimitedQty == eventsApplicationQty;
}
}
理論上 Services 應該要是 static,不過若要讓 static class 可以被 DI 注入服務,似乎有點麻煩(參考 Reference),所以我還是先用土法煉鋼的方式,等之後再慢慢改善系統。
為了取得當前登入使用者的資訊,Controller 的建構子加入 UserManager<ApplicationUser>
,提供 DI 注入:
private readonly AppDbContext _context;
private readonly IWebHostEnvironment _env;
private readonly IEventsRepository _eventsRepository;
private readonly UserManager<ApplicationUser> _userManager;
public EventsController(AppDbContext context, IEventsRepository eventsRepository,
IWebHostEnvironment env,
UserManager<ApplicationUser> userManager)
{
_context = context;
_env = env;
_eventsRepository = eventsRepository;
_userManager = userManager;
}
新增報名的 Action:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> EventsEnroll(int? id)
{
Events Event = new Events();
try
{
if (id != null)
{
Event = await _eventsRepository.GetEventByIdAsync(id);
EventsApplyServices EventsApplyServices = new EventsApplyServices(_eventsRepository);
var isInEventsSalesTime = EventsApplyServices.IsInEventsSalesTime(Event);
var isApplicationLimitedQtyFull = await EventsApplyServices.IsApplicationLimitedQtyFull(Event);
var useId = User.FindFirstValue(ClaimTypes.NameIdentifier);
EventsEnroll EventsEnroll = new EventsEnroll()
{
Events = Event,
ApplicationUserId = useId
};
if (isInEventsSalesTime == true && isApplicationLimitedQtyFull == false)
{
await _eventsRepository.SaveUserInfoToEventsEnrollAsync(EventsEnroll);
TempData["Message"] = "報名成功";
}
else
{
TempData["Message"] = "報名失敗";
}
}
else
{
return BadRequest();
}
}
catch (Exception)
{
throw new Exception("報名失敗");
}
return RedirectToAction("Details", Event);
}
在 HTML 的最前方加入 Form Tag 與 Id 欄位:
<form asp-action="EventsEnroll" method="post" style="display:inline;">
<input type="hidden" asp-for="Id" />
最下方加入結束的 Form Tag 與 EventsEnroll 的 Submit Btn:
<input type="submit" value="報名" class="btn btn-primary" /> |
<a asp-action="Edit" asp-route-id="@Model.Id">Edit</a> |
<a asp-action="Index">Back to List</a>
</div>
</form>
services.AddHttpContextAccessor();
今天將加入了 UserManager,並且可以用來取 UserId, UserName 等資料,
也成功新增了報名儲存用戶資料的 Action。
明天將會完成取消報名以及在活動畫面顯示當前報名人數欄位。
那麼我們明天見!
[C#/Unity] 這不叫 Singleton,叫 Service Locator – Practice of Service Locator
[Architecture] Service Locator
How to get the current logged in user ID in ASP.NET Core?